package dao

import (
	"context"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"inventory/internal/constant"
	"time"

	"inventory/internal/model"
)

// GetFreezeOrder 获取冻结单
func (d *Dao) GetFreezeOrder(ctx context.Context, orderNumber string) (order *model.FreezeOrder, err error) {
	order = &model.FreezeOrder{}
	err = d.TransContext(ctx).Model(&model.FreezeOrder{}).Where("order_number = ?", orderNumber).Take(&order).Error
	if err != nil {
		err = d.processSqlError(err)
	}
	return
}

// GetFreezeOrderByID 获取冻结单
func (d *Dao) GetFreezeOrderByID(ctx context.Context, orderID uint64) (order *model.FreezeOrder, err error) {
	order = &model.FreezeOrder{}
	err = d.TransContext(ctx).Model(&model.FreezeOrder{}).Where("id = ?", orderID).Take(&order).Error
	if err != nil {
		err = d.processSqlError(err)
	}
	return
}

// GetFreezeOrderByRequestNumAndSource 获取冻结单
func (d *Dao) GetFreezeOrderByRequestNumAndSource(ctx context.Context, requestNum string, source int) (order *model.FreezeOrder, err error) {
	order = &model.FreezeOrder{}
	err = d.TransContext(ctx).Model(&model.FreezeOrder{}).Where("request_num = ? and source = ?", requestNum, source).Take(&order).Error
	if err != nil {
		err = d.processSqlError(err)
	}
	return
}

// FindFreezeOrderDetails 获取冻结详情
func (d *Dao) FindFreezeOrderDetails(ctx context.Context, orderID uint64) (details []*model.FreezeDetail, err error) {
	err = d.TransContext(ctx).Model(&model.FreezeDetail{}).Where("order_id = ?", orderID).Find(&details).Error
	if err != nil {
		err = d.processSqlError(err)
	}
	return
}

// FindFreezeOrderNonZeroDetails 获取冻结非0详情
func (d *Dao) FindFreezeOrderNonZeroDetails(ctx context.Context, orderID uint64) (details []*model.FreezeDetail, err error) {
	err = d.TransContext(ctx).Model(&model.FreezeDetail{}).Where(
		"order_id = ? and target_quantity != 0", orderID).Find(&details).Error
	if err != nil {
		err = d.processSqlError(err)
	}
	return
}

// MarkFreezeDetailConsumed 标记冻结单明细已消费
func (d *Dao) MarkFreezeDetailConsumed(ctx context.Context, orderID uint64, updateTime time.Time) (err error) {
	err = d.TransContext(ctx).Model(&model.FreezeDetail{}).Where("order_id = ?", orderID).Updates(map[string]interface{}{
		"consumed_quantity": gorm.Expr("inv_freeze_detail.target_quantity"),
		"update_time":       updateTime,
	}).Error
	if err != nil {
		err = d.processSqlError(err)
	}
	return
}

// FindExpiredFreezeOrder 查询已过期冻结单
func (d *Dao) FindExpiredFreezeOrder(ctx context.Context) (freezeOrders []*model.FreezeOrder, err error) {
	err = d.TransContext(ctx).Model(&model.FreezeOrder{}).Where("expire_time < now()").Find(&freezeOrders).Error
	if err != nil {
		err = d.processSqlError(err)
	}
	return
}

// 基于活动单号加载冻结单
func (d *Dao) LockFreezeOrdersByOrderNumbers(ctx context.Context, orderNumbers []string) (freezeOrders []*model.FreezeOrder, err error) {
	err = d.TransContext(ctx).Model(&model.FreezeOrder{}).Where(
		"order_number in ? AND status = ?", orderNumbers, constant.FreezeOrderInit).Clauses(
		clause.Locking{Strength: "UPDATE"}).Find(&freezeOrders).Error
	if err != nil {
		err = d.processSqlError(err)
	}
	return
}

// 基于活动单ID序列加载冻结单明细
func (d *Dao) FindFreezeValidDetailsByOrderIds(ctx context.Context, orderIDs []uint64) (details []*model.FreezeDetail, err error) {
	err = d.TransContext(ctx).Model(&model.FreezeDetail{}).Where(
		"order_id in ? AND valid_quantity != 0", orderIDs).Order("id asc").Find(&details).Error
	if err != nil {
		err = d.processSqlError(err)
	}
	return
}

// TransferFreezeDetail 活动冻结明细 => 实际订单冻结明细；数量视为已消费
func (d *Dao) TransferFreezeDetail(ctx context.Context, detailID uint64, quantity float64, updateTime time.Time) (err error) {
	err = d.TransContext(ctx).Model(&model.FreezeDetail{ID: detailID}).Updates(map[string]interface{}{
		"consumed_quantity": gorm.Expr("inv_freeze_detail.consumed_quantity + ?", quantity),
		"valid_quantity":    gorm.Expr("inv_freeze_detail.valid_quantity - ?", quantity),
		"update_time":       updateTime,
	}).Error
	if err != nil {
		err = d.processSqlError(err)
	}
	return
}

// UpdateCalculationRequest
func (d *Dao) UpdateCalculationRequest(ctx context.Context, calculationRequest *model.ProcessRequest,
	freezeOrderId uint64, now time.Time) (err error) {
	if err = d.Update(ctx, &calculationRequest, map[string]interface{}{
		"status":          constant.CalculateRequestFrozen,
		"freeze_order_id": freezeOrderId,
		"update_time":     now,
	}); err != nil {
		err = d.processSqlError(err)
	}
	return
}
